#include "Channel.h"
#include"Logger.h"
#include"EventLoop.h"

#include <sys/epoll.h>

const int Channel::KNoneEvent = 0;
const int Channel::KReadEvent = EPOLLIN | EPOLLPRI;
const int Channel::KWriteEvent = EPOLLOUT;

Channel::Channel(EventLoop *loop, int fd) : loop_(loop), fd_(fd), events_(0), revents_(0), index_(-1), tied_(false)
{
}

Channel::~Channel(){   
}

//防止当tcpConnection被手动remove时，channel还在执行回调
//一个弱智能指针指向tcpconnection
void Channel::tie(const std::shared_ptr<void>& obj){
    tie_ = obj;
    tied_ = true;
}

//当改变channel表示的fd的events事件后，update负责在poller中更改fd对应的epoll_ctl
//EventLoop有 -》 ChannelList+Poller
void Channel::update(){
    //通过channel所属的EventLoop，调用poller的相应方法，注册fd事件
    //add code
    loop_->updateChannel(this);
}
//在channel所属的EventLoop中把自己删除
void Channel::remove(){
    //addcode
    loop_->removeChannel(this);
}

//fd可读可写后，回调事件
//分为tie是否被绑定过
void Channel::headleEvent(Timestamp receiveTime)
{
    if(tied_){
        std::shared_ptr<void> guard = tie_.lock();
        if(guard){
            handleEventWithGuard(receiveTime);
        }
    }else{
        handleEventWithGuard(receiveTime);
    }
}

//根据revent_，以及poller通知的发生的具体事件，由channel调用对应的事件
void Channel::handleEventWithGuard(Timestamp receiveTime)
{
    LOG_INFO("channel handleEvent revents_:%d", revents_);
    //被挂断且无可读事件
    if((revents_ & EPOLLHUP) && !(revents_ & EPOLLIN)){
        if(closeCallback_){
            closeCallback_();
        }
    }
    //发生错误
    if(revents_ & EPOLLERR){
        if(errorCallback_){
            errorCallback_();
        }
    }
    //读取的数据中有带外数据，只触发 EPOLLPRI，不触发 EPOLLIN，外带数据就是加急数据
    if(revents_ & (EPOLLIN | EPOLLPRI)){
        if(readCallback_){
            readCallback_(receiveTime);
        }
    }
    //可写
    if(revents_ & EPOLLOUT){
        if(writeCallback_){
            writeCallback_();
        }
    }
}